#pragma once

#include "e2d/core/pch.h"
#include "e2d/core/Object.h"
#include "e2d/core/EntityMap.h"

namespace e2d
{

	struct Entity;

	struct  Scene :public Object
	{
		entt::registry rg;

		std::string m_Name;

		std::vector<std::shared_ptr<e2d::Entity>> m_Entities;

		std::vector<std::shared_ptr<e2d::Entity>> ExistEntities() const;

		EntityMap m_EditingEntity;
		
		EntityMap m_EditingCamera;
		
		EntityMap m_MainCamera;

		Scene();

		~Scene();

		std::shared_ptr<e2d::Entity> CreateEntityFrom(const std::string& dir,
			const std::function<void(e2d::Entity*, const std::string&)>& func );

		void RegisterEntity(std::shared_ptr<e2d::Entity> entity);

		std::shared_ptr<e2d::Entity> NewEntity(const std::string& entityName = "Entity");

		std::shared_ptr<e2d::Entity> NewEntityOnParent(e2d::Entity* parent);

		void AddEntityToParent(std::shared_ptr<e2d::Entity> child, e2d::Entity* parent);

		bool HasEntity(const std::string& uid) const;

		template<typename T>
		std::vector<e2d::Entity*> GetComponentEntities() 
		{
			std::vector<e2d::Entity*> res;

			auto view = rg.view<T>();
			for (auto e : view)
			{
				auto& component = rg.get<T>(e);
				res.push_back(component.m_Entity);
			}
			return res;
		}
		template<typename T>
		std::vector<e2d::EntityMap> GetComponentEntitiesMap()
		{
			std::vector<e2d::EntityMap> res;
			auto entities = GetComponentEntities<T>();

			for (auto e : entities)
			{
				res.push_back(e);
			}
			return res;
		}


		std::shared_ptr<e2d::Entity> GetEntity(const std::string& uuid)
		{
			auto it = m_EntityMap.find(uuid);
			if (it != m_EntityMap.end())
			{
				return it->second;
			}
			return 0;
		};

		void OnLoad();

		void UploadEntityMap();

		void ProcessAllEntities(std::vector<std::shared_ptr<e2d::Entity>>& target, std::shared_ptr<e2d::Entity> e);

		bool RemoveChidren(const std::vector<std::string>& uuids);

		bool SnatchEntityAsChild(const std::string& uuid);

		bool SnatchEntityInstAsChild( std::shared_ptr<e2d::Entity> e);

		void SetAllExist();
	public:
		std::vector<std::shared_ptr<e2d::Entity>> m_AllEntitiesCalculated;

		std::vector<std::shared_ptr<e2d::Entity>> m_AllEntitiesCalculatedNoPrefeb;

		std::unordered_map<std::string, std::shared_ptr<e2d::Entity>> m_EntityMap;

		e2d::Input* m_Input{ 0 };

		e2d::Timer* m_Timer{ 0 };

		void SetInput(e2d::Input* input)
		{
			m_Input = input;
		}

		void SetTimer(e2d::Timer* timer)
		{
			m_Timer = timer;
		}

		void SetTimerAndInput(e2d::Timer* timer, e2d::Input* input)
		{
			m_Timer = timer;
			m_Input = input;

		}

	};

}
